package com.quyl.poi.service;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.json.JSONUtil;
import com.quyl.poi.dto.SheetCondition;
import com.quyl.poi.enums.KeyTypeEnum;
import com.quyl.poi.util.Constant;
import com.quyl.poi.util.PoiExcelUtil;
import org.apache.poi.ss.usermodel.Workbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;

public class ExcelCallable implements Callable {
    private static final Logger logger = LoggerFactory.getLogger(ExcelCallable.class);
    private String path;

    public ExcelCallable(String path) {
        this.path = path;
    }

    @Override
    public Map<String, Object> call() {
        logger.debug("任务启动,当前线程为{}", Thread.currentThread().getName());
//        long start = System.currentTimeMillis();
        Map<String, Object> maps = readExcel(path);
//        long end = System.currentTimeMillis();
//        logger.info("{}线程耗时：{}ms",Thread.currentThread(),end-start);
        logger.debug("任务执行完了,当前线程为{}", Thread.currentThread().getName());
        return maps;
    }

    public Map<String, Object> readExcel(String filePath) {
        Workbook workbook = null;
        try {
            String fileType = filePath.substring(filePath.lastIndexOf("."));
            workbook = PoiExcelUtil.getWorkbook(filePath, fileType);
            if (workbook == null) {
                logger.info("获取workbook对象失败");
                return null;
            }
            return analysisExcel(workbook);
        } catch (Exception e) {
            logger.error("读取Excel文件失败" + filePath + "错误信息", e);
            return null;
        } finally {
            try {
                if (null != workbook) {
                    workbook.close();
                }
            } catch (Exception e) {
                logger.error("关闭数据流出错！错误信息：", e);
                return null;
            }

        }
    }

    /**
     * 解析Excel文件中所有的表，返回数据对象
     *
     * @param workbook
     * @return
     */
    public Map<String, Object> analysisExcel(Workbook workbook) {
        Map<String, Object> map = new HashMap<>();
        logger.debug("-------------{} start......------------------", workbook.getSheetAt(0).getSheetName());
        SheetCondition sheetCondition = SheetCondition.builder().cellInfo(new HashMap<Integer, String>() {{
            put(0, "key");
            put(1, "value");
        }}).startRow(0).keyType(KeyTypeEnum.ROW_KEY.getCode()).useCellNums(Arrays.asList(0, 1)).indexNum(0).build();

        List<Map<String, Object>> listRes = PoiExcelUtil.doSheetRowList(PoiExcelUtil.getMapKeys(workbook.getSheetAt(0), sheetCondition), workbook.getSheetAt(0), sheetCondition);
        if (CollectionUtil.isNotEmpty(listRes)) {
            Map<String, Object> stringObjectMap = listRes.stream().filter(item -> item.get("key").equals("模型英文")).findFirst().get();//.
            map.put("tableName", stringObjectMap.get("value"));
        }
        map.put("basicInfo", listRes);
        logger.debug("基本信息:{}", JSONUtil.toJsonStr(map.get("basicInfo")));


        SheetCondition sheetCondition2 = SheetCondition.builder().startRow(4).keyType(KeyTypeEnum.COL_KEY.getCode()).useCellNums(Arrays.asList(0, 9, 10, 13, 16, 17, 18, 21)).indexNum(0).build();
        List<Map<String, String>> mapKeys2 = PoiExcelUtil.getMapKeys(workbook.getSheetAt(1), sheetCondition);
        map.put("modelDefine", doSheet(workbook, sheetCondition2, 1, mapKeys2));
        logger.debug("----------------------{} start....----------------------", workbook.getSheetAt(1).getSheetName());
        logger.debug("模型定义:{}", JSONUtil.toJsonStr(map.get("modelDefine")));

        List<Map<String, String>> mapKeys3 = PoiExcelUtil.getMapKeys(workbook.getSheetAt(2), sheetCondition);

        SheetCondition sheetCondition31 = SheetCondition.builder().startRow(1).keyType(KeyTypeEnum.COL_KEY.getCode()).useCellNums(Arrays.asList(0, 1, 2, 3)).indexNum(0).build();
        map.put("dataSource", doSheet(workbook, sheetCondition31, 2, mapKeys3));
        logger.debug("----------------------3.数据源信息----------------------");
        logger.debug("数据源信息:{}", JSONUtil.toJsonStr(map.get("dataSource")));

        SheetCondition sheetCondition32 = SheetCondition.builder().startRow(1).keyType(KeyTypeEnum.COL_KEY.getCode()).useCellNums(Arrays.asList(5, 6)).indexNum(5).build();
        map.put("algorithmDesc", doSheet(workbook, sheetCondition32, 2, mapKeys3));
        logger.debug("----------------------4.算法整体描述说明----------------------");
        logger.debug("算法整体描述说明:{}", JSONUtil.toJsonStr(map.get("algorithmDesc")));

        SheetCondition sheetCondition33 = SheetCondition.builder().startRow(1).keyType(KeyTypeEnum.COL_KEY.getCode()).useCellNums(Arrays.asList(8, 9)).indexNum(8).build();
        map.put("checkRule", doSheet(workbook, sheetCondition33, 2, mapKeys3));
        logger.debug("----------------------5.校验规则----------------------");
        logger.debug("校验规则:{}", JSONUtil.toJsonStr(map.get("checkRule")));

        SheetCondition sheetCondition34 = SheetCondition.builder().startRow(1).keyType(KeyTypeEnum.COL_KEY.getCode()).useCellNums(Arrays.asList(11, 12)).indexNum(11).build();
        map.put("useDesc", doSheet(workbook, sheetCondition34, 2, mapKeys3));
        logger.debug("----------------------6.使用说明----------------------");
        logger.debug("使用说明:{}", JSONUtil.toJsonStr(map.get("useDesc")));
        /*Map<String, CompletableFuture<Map<String, Object>>> futureMap = new HashMap<>();
        CompletableFuture<Map<String, Object>> modelDefineFuture = CompletableFuture.supplyAsync(() -> {
            SheetCondition sheetCondition2 = SheetCondition.builder().startRow(4).keyType(KeyTypeEnum.COL_KEY.getCode()).useCellNums(Arrays.asList(0, 9, 10, 13, 16, 17, 18, 21)).indexNum(0).build();
            List<Map<String, String>> mapKeys2 = PoiExcelUtil.getMapKeys(workbook.getSheetAt(1), sheetCondition);
//            map.put("modelDefine", doSheet(workbook, sheetCondition2, 1, mapKeys2));
//            logger.debug("----------------------{} start....----------------------", workbook.getSheetAt(1).getSheetName());
//            logger.debug("模型定义:{}", JSONUtil.toJsonStr(map.get("modelDefine")));
            return doSheet(workbook, sheetCondition2, 1, mapKeys2);
        });
        futureMap.put("modelDefine", modelDefineFuture);

        List<Map<String, String>> mapKeys3 = PoiExcelUtil.getMapKeys(workbook.getSheetAt(2), sheetCondition);

        futureMap.put("dataSource", CompletableFuture.supplyAsync(() -> {
            SheetCondition sheetCondition31 = SheetCondition.builder().startRow(1).keyType(KeyTypeEnum.COL_KEY.getCode()).useCellNums(Arrays.asList(0, 1, 2, 3)).indexNum(0).build();
//            map.put("dataSource", doSheet(workbook, sheetCondition31, 2, mapKeys3));
//            logger.debug("----------------------3.数据源信息----------------------");
//            logger.debug("数据源信息:{}", JSONUtil.toJsonStr(map.get("dataSource")));
            return doSheet(workbook, sheetCondition31, 2, mapKeys3);
        }));

        futureMap.put("algorithmDesc", CompletableFuture.supplyAsync(() -> {
            SheetCondition sheetCondition32 = SheetCondition.builder().startRow(1).keyType(KeyTypeEnum.COL_KEY.getCode()).useCellNums(Arrays.asList(5, 6)).indexNum(5).build();
//            map.put("algorithmDesc", doSheet(workbook, sheetCondition32, 2, mapKeys3));
//            logger.debug("----------------------4.算法整体描述说明----------------------");
//            logger.debug("算法整体描述说明:{}", JSONUtil.toJsonStr(map.get("algorithmDesc")));
            return doSheet(workbook, sheetCondition32, 2, mapKeys3);
        }));

        futureMap.put("checkRule", CompletableFuture.supplyAsync(() -> {
            SheetCondition sheetCondition33 = SheetCondition.builder().startRow(1).keyType(KeyTypeEnum.COL_KEY.getCode()).useCellNums(Arrays.asList(8, 9)).indexNum(8).build();
//            map.put("checkRule", doSheet(workbook, sheetCondition33, 2, mapKeys3));
//            logger.debug("----------------------5.校验规则----------------------");
//            logger.debug("校验规则:{}", JSONUtil.toJsonStr(map.get("checkRule")));
            return doSheet(workbook, sheetCondition33, 2, mapKeys3);
        }));

        futureMap.put("useDesc", CompletableFuture.supplyAsync(() -> {
            SheetCondition sheetCondition34 = SheetCondition.builder().startRow(1).keyType(KeyTypeEnum.COL_KEY.getCode()).useCellNums(Arrays.asList(11, 12)).indexNum(11).build();
//            map.put("useDesc", doSheet(workbook, sheetCondition34, 2, mapKeys3));
//            logger.debug("----------------------6.使用说明----------------------");
//            logger.debug("使用说明:{}", JSONUtil.toJsonStr(map.get("useDesc")));
            return doSheet(workbook, sheetCondition34, 2, mapKeys3);
        }));


        for (Map.Entry<String, CompletableFuture<Map<String, Object>>> entry : futureMap.entrySet()) {
            try {
//                while (!entry.getValue().isDone()) ;
                map.put(entry.getKey(), entry.getValue().get());
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            } catch (ExecutionException e) {
                throw new RuntimeException(e);
            }
        }*/
//        logger.debug("最终结果{}", JSONUtil.toJsonStr(map));
        return map;
    }

    public Map<String, Object> doSheet(Workbook workbook, SheetCondition sheetCondition, int sheetIndex, List<Map<String, String>> mapKeys) {
        List<Map<String, String>> labels = mapKeys.stream().filter(src -> sheetCondition.getUseCellNums().contains(Integer.valueOf(src.get(Constant.ID).substring(5, src.get(Constant.ID).length())))).collect(Collectors.toList());
        Map<String, Object> mapRes = new HashMap<>();
        mapRes.put(Constant.LABEL, labels);
        List<Map<String, Object>> listRes = PoiExcelUtil.doSheetRowList(mapKeys, workbook.getSheetAt(sheetIndex), sheetCondition);
        mapRes.put(Constant.LABEL_DATA, listRes);
        return mapRes;
    }

}
